
//#########################################################################
//
// (C) Copyright by Hachreak
//       Released under GPL v2.
//       Author : Hachreak (hachreak at gmail dot com)
//       WebSite: www.secondlifelab.it
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
//#########################################################################



//********************* Load Notecard ***************************************************************

// Nome della notecard
string LNC_name = "NotecardInfo";

// lista dei nomi delle variabili
list LNC_names  = [];
// lista dei valori delle variabili
list LNC_values = [];

integer LNC_line = 0;
key LNC_query;

integer LNC_error = 0;

integer LNC_timeout = 30;
//***************************************************************************************************

string LNCgetVar(string name){
	string value = "";
	
	integer index = llListFindList(LNC_names, [name]);
	if(index != -1){
		value = llList2String(LNC_values, index);
	}
	return value;
}

string LNCgetVarD(string name, string default_value){
	string value = "";
	
	integer index = llListFindList(LNC_names, [name]);
	if(index != -1){
		value = llList2String(LNC_values, index);
	}
	
	/// if is empty, init with default value
	if(value == ""){
		return default_value;
	}

	return value;
}




integer STRcontain(string source, string pattern){
	if(llSubStringIndex(source, pattern) >= 0){
		return TRUE;
	}else{
		return FALSE;
	}
}

integer STRinitWith(string source, string pattern){
	if(llSubStringIndex(source, pattern) == 0){
		return TRUE;
	}else{
		return FALSE;
	}
}

// TODO controllare che funzioni!
integer STRfinishWith(string source, string pattern){
	if(llSubStringIndex(source, pattern) == (llStringLength(source) - llStringLength(pattern) - 1)){
		return TRUE;
	}else{
		return FALSE;
	}
}

string STRreplace(string source, string search, string replace){
	list explode = llParseString2List(source, [], [search]);
	integer i;
	string output = "";
	for(i=0;i<llGetListLength(explode);i++){
		string block = llList2String(explode, i);
		if(block == search){
			output += replace;
		}else{
			output += block;
		}
	}

	return output;
}

// Trasforma una lista in una stringa.
string STRlist2string(list lista){
	string str = "";
	integer i;

	for(i=0;i<llGetListLength(lista);i++){
		str += llList2String(lista, i);
	}

	return str;
}

// Es.  
//     source="Hello, how are you?";
//     llSay(0,STRremoveFirst(source, llStringLength("Hello, ")));
//          // output:
//          // how are you?
string STRremoveFirst(string source, integer start){
	return llGetSubString(source, start, llStringLength(source));
}

string STRremoveLast(string source, integer end){
	return llGetSubString(source, 0, end);
}

// Ottieni una sub stringa di source che parte da zero
// fino a quando non trova la prima occorrenza di pattern escluso
// TODO da testare!
string STRgetFinoAFirst(string source, string pattern){
	return llGetSubString(source, 0, llSubStringIndex(source, pattern) - 1);
}


//################### HTTP_REQUEST PROTOCOL (HRP) ##########################
//
// Stato utilizzato per fare la richiesta http
//
// variabili in INPUT:
//		HRP_url
//		HRP_get
//		
// variabili in OUTPUT:
//		HRP_status
//		HRP_body
//
// Alla conclusione della richiesta http, viene invocato lo
// stato "HRP_out".
// In caso di timeout della connessione, "HRP_status" avra' il
// valore -1.
//
// Librerie usate: strings
//

// url da contattare
string HRP_url = "";
// parametri da passare nel post
//list HRP_post;
// parametri da passare nel gel
list HRP_get;
// id rilasciato per riconoscere la connessione
key HRP_id;
// timeout della connessione (15 secondi)
integer HRP_timeout = 15;
// codice di status della connessione
integer HRP_status;
// corpo della risposta
string HRP_body;

// stringa che indica il successo dell'operazione
string HRP_OK    = "ok";
// insuccesso dell'operazione
string HRP_ERROR = "error";

// status: timeout of server
integer HRP_STATUS_TIMEOUT = -1;

// aggiungi una variabile nel post
HRPaddHttpGet(string name, string value){
	HRP_get += [name ];
	HRP_get += ["=" + value + "&"];
}

// set di un nuovo timeout
HRPsetTimeout(integer timout){
	HRP_timeout = timout;
}

// aggiungi una variabile nel post
//HRPaddHttpPost(string name, string value){
//	HRP_post += [name ];
//	HRP_post += ["=" + value + "&"];
//}

// modifica dei parametri.
// ritorna un valore >= 0 se ha sostutuito (indicala posizione 
// dove ha sostituito) o negativo se non ha trovato il parametro
// TODO controllare se funzia!
integer HRPreplaceGet(string name, string value){
	integer pos = llListFindList(HRP_get, [name]);

	if((pos != -1) && (pos % 2 == 0)){
		// elimino i vecchi valori
		HRP_get = llDeleteSubList(HRP_get, pos, pos + 1);

		// aggiunti i nuovi
		HRPaddHttpGet(name, value);
	}else{
		return -1;
	}

	return 0;
}

// modifica dei parametri.
// ritorna un valore >= 0 se ha sostutuito (indicala posizione 
// dove ha sostituito) o negativo se non ha trovato il parametro
// TODO controllare se funzia!
//integer HRPreplacePost(string name, string value){
//	integer pos = llListFindList(HRP_post, [name]);

//	if((pos != -1) && (pos % 2 == 0)){
		// elimino i vecchi valori
//		HRP_post = llDeleteSubList(HRP_post, pos, pos + 1);

		// aggiunti i nuovi
//		HRPaddHttpPost(name, value);
//	}else{
//		return -1;
//	}
//}

// reset del vettore GET
HRPresetHttpGet(){
	HRP_get = [];
}

// reset del vettore POST
//HRPresetHttpPost(){
//	HRP_post = [];
//}


// URL of php script server
//string site_url = "http://www.secondlifelab.it/rss.php";

// URL of RSS to read
string url2get = "http://www.secondlifelab.it/index.php?option=com_rss&feed=RSS2.0&no_html=1";

string version = "1.0.0";

integer link;

// number of news to view
integer number_of_news;

// lista contenente la cache
list newsCache_text;
list newsCache_number;

//integer timeout;

// Function for encode the url of RSS to send at the phph script
string encode_url(string url){
    list chars = ["&","?","=","#","$"];
    list chars_enc = ["$1","$2","$3","$4","$5"];

    list lista = llParseString2List($url,[],chars);

    integer i;
    string url_enc = "";
    for(i=0; i<llGetListLength(lista); i++){
        string element = llList2String(lista,i);

        integer n;
        if((n = llListFindList(chars,[element])) != -1){
            url_enc += llList2String(chars_enc,n);
        }else{
            url_enc += element;
        }
    }

    return url_enc;
}

default{

    state_entry(){
	// Set "touch text" to "Read News"
        llSetTouchText("Read News");

	// set name of notecard
	LNC_name = "NotecardInfo";

	// azzero la cache
	newsCache_text = [];
	newsCache_number = [];

	// read notecard
	state LNC_in;

    }

    // On REZ reset all script.
    on_rez(integer start_param) {
        llResetScript();
    }

    changed(integer change){
    	if (change & CHANGED_INVENTORY) {
		// probabilmente, e' stata modificata la notecard
		llResetScript();
	}
    }

}


state LNC_in {
	state_entry() {
		LNC_error = FALSE;

		LNC_query = llGetNotecardLine(LNC_name, LNC_line);

		// timer in caso di timeout
		llSetTimerEvent(LNC_timeout);
	}

    dataserver(key queryid, string data) {
        if(LNC_query == queryid){
		if (data != EOF) {
	            list param = llParseString2List(data, ["="], []);
	            if(llGetListLength(param) >= 2){
	                // c'e sia il nome che il valore della variabile
        	        LNC_names  += [llList2String(param, 0)];
                	LNC_values += [llGetSubString(data, llStringLength(llList2String(param, 0)) + 1, llStringLength(data))];
        	    }
			// Richiama la lettura di una nuova riga
			LNC_query = llGetNotecardLine(LNC_name, ++LNC_line);
		}else{
			// Finito!
			state LNC_out;
		}
	}
   }

   timer(){
   	LNC_error = TRUE;

	state LNC_out;
   }

   state_exit(){
   	// leva il timer
   	llSetTimerEvent(0);
   }
}
//***************************************************************************************************

state HRP_in{
	state_entry(){
		if(!STRcontain(HRP_url, "?")){
			HRP_url += "?";
		}else{
			// se l'url contiene parametri devo far terminare la
			// stringa con '&' per inserire i parametri aggiuntivi
			if(!STRfinishWith(HRP_url, "&")){
				HRP_url += "&";
			}
		}

		HRP_id = llHTTPRequest(HRP_url+STRlist2string(HRP_get),[HTTP_METHOD,"GET"],"");//STRlist2string(HRP_post));

		// inizializzo lo status
		HRP_status = 0;

		llSetTimerEvent(HRP_timeout); 
	}

	http_response(key request_id, integer status, list metadata, string body){
		// controllo che sia la mia richiesta 
		if(HRP_id == request_id){
			// salvo lo status della connessione
			HRP_status = status;
			// salvo la risposta
			HRP_body = body;

			state HRP_out;
		}
	}

	timer(){
		// timeout della connessione!
		HRP_status = HRP_STATUS_TIMEOUT;
		state HRP_out;
	}

        state_exit(){
     	        // leva il timer
	   	llSetTimerEvent(0);
	}

}

// ####################################################

state LNC_out{
	state_entry(){
		// RSS da controllare
		url2get  = LNCgetVar("url2get");

		// server php che fa da filtro
		HRP_url = LNCgetVar("site_url");

		// number of news to view
		number_of_news = (integer)LNCgetVarD("number_of_news", "5");

		// set timeout for reloading the titles and reset cache
		//timeout = (integer)LNCgetVarD("timeout", "500");
		// manda un msg di reset a tutti gli script
		llMessageLinked(LINK_ALL_OTHERS, 0, "", NULL_KEY);

		// start!
		state first;
	}
}

state first{
    state_entry(){
    	//llSetTimerEvent(timeout);

	// Send a msg to root for request the list of title
	//llMessageLinked(LINK_ROOT, 2, "", NULL_KEY);
    }

    // sender_num is the link number of the sending object in the set.
    // link_number - children che ha fatto la richiesta
    link_message(integer sender_num, integer link_number, string msg, key id) {
        link = link_number;

	integer number = link_number - 3;
		
	// reset param
	HRPresetHttpGet();

        if(link == 2){
		if(msg == "version"){
		    // Get version
		    HRPaddHttpGet("op","version");
		}else{
		    // Get the titles
		    HRPaddHttpGet("op","titles");
		    HRPaddHttpGet("number",(string)number_of_news);
		}
        }else{// devo leggere una nuova news

	    integer index;
   	    // guardo se ho gia' questa news nella cache
	    if((index = llListFindList( newsCache_number, [number] )) != -1){
	    	// la news e' gia' nella cache
		llMessageLinked(LINK_ALL_OTHERS, link, llList2String(newsCache_text, index), NULL_KEY);
	
		// fine
		return;
	    }

	    // Get the body of a news
	    HRPaddHttpGet("op","body");
	    HRPaddHttpGet("number",(string)number);
        }

	// Send Region Name and Pos
	HRPaddHttpGet("region",llGetRegionName());

	// Send position of myrss
	vector pos = llGetPos();
	HRPaddHttpGet("coo_x",(string)pos.x);
	HRPaddHttpGet("coo_y",(string)pos.y);
	HRPaddHttpGet("coo_z",(string)pos.z);

	// Send version of myrss
	HRPaddHttpGet("version",version);

	// url of rss
	HRPaddHttpGet("url",encode_url(url2get));

	// start request
	state HRP_in;
    }

    // On REZ reset all script.
    on_rez(integer start_param) {
        llResetScript();
    }
	
    changed(integer change){
    	if (change & CHANGED_INVENTORY) {
		// probabilmente, e' stata modificata la notecard
		llResetScript();
	}
    }

    timer(){
    	llResetScript();
    }
}

state HRP_out{

    state_entry(){
    	if(HRP_status == 200){
		if(link == 2){
			// svuota la cache
			newsCache_text = [];
			newsCache_number = [];
		}else{
			// salvo la news in cache
			newsCache_text   += [HRP_body];
			newsCache_number += [link - 3];
		}

		// manda la news
		llMessageLinked(LINK_ALL_OTHERS, link, HRP_body, NULL_KEY);
	}else if(HRP_status != 0){
		// si e' verificato qualche errore, resetta tutto!
		llMessageLinked(LINK_ALL_OTHERS, -1, "", NULL_KEY);
	}

	// aspetta un nuovo comando
	state first;

    }

    changed(integer change){
    	if (change & CHANGED_INVENTORY) {
		// probabilmente, e' stata modificata la notecard
		llResetScript();
	}
    }

    timer(){
    	llResetScript();
    }

}

